package com.cloud.school.app.service.impl;

import com.cloud.school.app.entity.TbMessage;
import com.cloud.school.app.mapstruct.IMessageConvertMapper;
import com.cloud.school.app.model.MesageEngineModel;
import com.cloud.school.app.model.MessageModel;
import com.cloud.school.app.model.UserModel;
import com.cloud.school.app.repository.TbMessageMapper;
import com.cloud.school.app.service.MessageService;
import com.cloud.school.app.service.UserService;
import com.cloud.school.app.util.IdWorker;
import com.cloud.school.app.util.Pager;
import com.cloud.school.app.util.enumeration.MessageReceiveType;
import com.cloud.school.app.util.exception.SystemHandleException;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.cloud.school.app.config.CloudSchoolProperties.MAX_PAGE_PER_COUNT;
import static com.cloud.school.app.config.CloudSchoolProperties.PAGE_PER_COUNT;

/**
 * @ClassName MessageServiceImpl
 * @Description TODO
 * @Author 36297
 * @Date 2018/12/12 22:06
 * @Version 1.0
 */
@Service
public class MessageServiceImpl implements MessageService {

    public static final String USER_NEW_MESSAGE = "newMessage.userId";

    @Autowired
    private TbMessageMapper tbMessageMapper;
    @Autowired
    private IMessageConvertMapper messageConvertMapper;
    @Autowired
    private IdWorker messageIdWorker;
    @Autowired
    private UserService userService;
    @Autowired
    private CacheService cacheService;

    @Override
    @Transactional
    public boolean save(MessageModel messageModel) {
        if (messageModel.getSendUid() != null && messageModel.getSendUid().equals(messageModel.getReceiveId())) {
            throw new SystemHandleException("禁止自己给自己发消息!");
        }
        TbMessage tbMessage = messageConvertMapper.modelToEntity(messageModel);
        tbMessage.setId(messageIdWorker.nextId());
        if (MessageReceiveType.USER.getCode() == messageModel.getReceiveType()) {
            cacheService.hashIncr(USER_NEW_MESSAGE + messageModel.getReceiveId(), String.valueOf(tbMessage.getSendUid()));
        }
        return tbMessageMapper.insertSelective(tbMessage) > 0;
    }

    @Override
    public Pager<MessageModel> selectBySendUidAndReceiveUId(Long sendUid, Long receiveId, Integer messageReceiveType, Integer status, int pNo) {
        PageHelper.startPage(pNo, MAX_PAGE_PER_COUNT);
        TbMessage tbMessage = new TbMessage();
        tbMessage.setSendUid(sendUid);
        tbMessage.setReceiveId(receiveId);
        tbMessage.setReceiveType(messageReceiveType);
        tbMessage.setStatus(status);
        List<TbMessage> messages = tbMessageMapper.select(tbMessage);
        Pager result = Pager.build(messages);
        messages.sort(Comparator.comparingLong(TbMessage::getSendTime));
        result.setResultList(appendSendUser(messageConvertMapper.entityToModel(messages)));
        return result;
    }

    @Override
    public List<MessageModel> selectBySendUidAndReceiveUId(Long sendUid, Long receiveId, Integer messageReceiveType, Integer status) {
        TbMessage tbMessage = new TbMessage();
        tbMessage.setSendUid(sendUid);
        tbMessage.setReceiveId(receiveId);
        tbMessage.setReceiveType(messageReceiveType);
        tbMessage.setStatus(status);
        return appendSendUser(messageConvertMapper.entityToModel(tbMessageMapper.select(tbMessage)));
    }

    @Override
    public Pager<MessageModel> selectUserMessage(Long Uid, Integer status, int pNo) {
        PageHelper.startPage(pNo, PAGE_PER_COUNT);
        List<TbMessage> messages = tbMessageMapper.selectSendReceiveMessageByUserId(status, Uid);
        Pager result = Pager.build(messages);
        List<MessageModel> messageModels = appendSendUser(selectByIds(messages.stream().map(TbMessage::getId).collect(Collectors.toList())));
        List<MesageEngineModel> mesageEngineModels = messageModels.stream().map(m -> {
            MesageEngineModel me = new MesageEngineModel(m);
            me.setNewMessageCount(cacheService.hashGet(USER_NEW_MESSAGE + Uid, String.valueOf(m.getSendUid().equals(Uid) ? m.getReceiveId() : m.getSendUid())));
            return me;
        }).collect(Collectors.toList());
        result.setResultList(mesageEngineModels);
        return result;
    }

    @Override
    public Pager<MessageModel> selectUserMessage(Long Uid, int pNo) {
        return selectUserMessage(Uid, null, pNo);
    }

    @Override
    public Pager<MessageModel> selectUserMessageByFriendUid(Long Uid, Long friendUid, Integer status, int pNo) {
        PageHelper.startPage(pNo, PAGE_PER_COUNT);
        List<TbMessage> messages = tbMessageMapper.selectByStatusAndSendUidReceiveIdIn(status, Lists.newArrayList(Uid, friendUid));
        Pager result = Pager.build(messages);
        result.setResultList(appendSendUser(messageConvertMapper.entityToModel(messages)));
        cacheService.hashDelete(USER_NEW_MESSAGE + Uid, String.valueOf(friendUid));
        return result;
    }

    private List<MessageModel> appendSendUser(List<MessageModel> messageModels) {
        List<Long> userIds = messageModels.stream().map(MessageModel::getSendUid).distinct().collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(userIds)) {
            Map<Long, UserModel> userModels = userService.queryByIds(userIds).stream().collect(Collectors.toMap(u -> u.getId(), u -> u));
            messageModels.forEach(m -> m.setSender(userModels.get(m.getSendUid())));
        }
        return messageModels;
    }

    @Override
    public Pager<MessageModel> selectUserMessageByFriendUid(Long Uid, Long friendUid, int pNo) {
        return selectUserMessageByFriendUid(Uid, friendUid, null, pNo);
    }

    @Override
    public Pager<MessageModel> selectGroupMessageByReceiveId(Long receiveId, Integer status, int pNo) {
        return selectBySendUidAndReceiveUId(null, receiveId, MessageReceiveType.GROUP.getCode(), status, pNo);
    }

    @Override
    public Pager<MessageModel> selectGroupMessageByReceiveId(Long receiveId, int pNo) {
        return selectBySendUidAndReceiveUId(null, receiveId, MessageReceiveType.GROUP.getCode(), null, pNo);
    }

    @Override
    public Pager<MessageModel> selectChatMessageByReceiveId(Long receiveId, Integer status, int pNo) {
        return selectBySendUidAndReceiveUId(null, receiveId, MessageReceiveType.CHAT_ROOM.getCode(), status, pNo);
    }

    @Override
    public Pager<MessageModel> selectChatMessageByReceiveId(Long receiveId, int pNo) {
        return selectBySendUidAndReceiveUId(null, receiveId, MessageReceiveType.CHAT_ROOM.getCode(), null, pNo);
    }

    @Override
    public List<MessageModel> selectByIds(List<Long> ids) {
        if (!CollectionUtils.isEmpty(ids)) {
            Example example = new Example(TbMessage.class);
            example.createCriteria().andIn("id", ids);
            return messageConvertMapper.entityToModel(tbMessageMapper.selectByExample(example));
        }
        return Lists.newArrayList();
    }
}
